ChoiceType Field (select drop

您所在的位置:网站首页 choice data ChoiceType Field (select drop

ChoiceType Field (select drop

2024-07-12 09:51| 来源: 网络整理| 查看: 265

A multi-purpose field used to allow the user to "choose" one or more options. It can be rendered as a select tag, radio buttons, or checkboxes.

To use this field, you must specify either choices or choice_loader option.

Rendered as can be various tags (see below) Default invalid message The selected choice is invalid. Legacy invalid message The value {{ value }} is not valid. Parent type FormType Class ChoiceType

Tip

The full list of options defined and inherited by this form type is available running this command in your app:

1 2 # replace 'FooType' by the class name of your form type $ php bin/console debug:form FooType Example Usage

The easiest way to use this field is to define the choices option to specify the choices as an associative array where the keys are the labels displayed to end users and the array values are the internal values used in the form field:

1 2 3 4 5 6 7 8 9 10 use Symfony\Component\Form\Extension\Core\Type\ChoiceType; // ... $builder->add('isAttending', ChoiceType::class, [ 'choices' => [ 'Maybe' => null, 'Yes' => true, 'No' => false, ], ]);

This will create a select drop-down like this:

If the user selects No, the form will return false for this field. Similarly, if the starting data for this field is true, then Yes will be auto-selected. In other words, the choice of each item is the value you want to get/set in PHP code, while the key is the label that will be shown to the user.

Advanced Example (with Objects!)

This field has a lot of options and most control how the field is displayed. In this example, the underlying data is some Category object that has a getName() method:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 use App\Entity\Category; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; // ... $builder->add('category', ChoiceType::class, [ 'choices' => [ new Category('Cat1'), new Category('Cat2'), new Category('Cat3'), new Category('Cat4'), ], // "name" is a property path, meaning Symfony will look for a public // property or a public method like "getName()" to define the input // string value that will be submitted by the form 'choice_value' => 'name', // a callback to return the label for a given choice // if a placeholder is used, its empty value (null) may be passed but // its label is defined by its own "placeholder" option 'choice_label' => function (?Category $category): string { return $category ? strtoupper($category->getName()) : ''; }, // returns the html attributes for each option input (may be radio/checkbox) 'choice_attr' => function (?Category $category): array { return $category ? ['class' => 'category_'.strtolower($category->getName())] : []; }, // every option can use a string property path or any callable that get // passed each choice as argument, but it may not be needed 'group_by' => function (): string { // randomly assign things into 2 groups return rand(0, 1) === 1 ? 'Group A' : 'Group B'; }, // a callback to return whether a category is preferred 'preferred_choices' => function (?Category $category): bool { return $category && 100 < $category->getArticleCounts(); }, ]);

You can also customize the choice_name of each choice. You can learn more about all of these options in the sections below.

Caution

The placeholder is a specific field, when the choices are optional the first item in the list must be empty, so the user can unselect. Be sure to always handle the empty choice null when using callbacks.

Select Tag, Checkboxes or Radio Buttons

This field may be rendered as one of several HTML fields, depending on the expanded and multiple options:

Element Type Expanded Multiple select tag false false select tag (with multiple attribute) false true radio buttons true false checkboxes true true Customizing each Option's Text (Label)

Normally, the array key of each item in the choices option is used as the text that's shown to the user. But that can be completely customized via the choice_label option. Check it out for more details.

Grouping Options

You can group the elements of a into by passing a multi-dimensional choices array:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 use Symfony\Component\Form\Extension\Core\Type\ChoiceType; // ... $builder->add('stockStatus', ChoiceType::class, [ 'choices' => [ 'Main Statuses' => [ 'Yes' => 'stock_yes', 'No' => 'stock_no', ], 'Out of Stock Statuses' => [ 'Backordered' => 'stock_backordered', 'Discontinued' => 'stock_discontinued', ], ], ]);

To get fancier, use the group_by option instead.

Field Options choices

type: array default: []

This is the most basic way to specify the choices that should be used by this field. The choices option is an array, where the array key is the item's label and the array value is the item's value:

1 2 3 4 5 6 7 8 9 use Symfony\Component\Form\Extension\Core\Type\ChoiceType; // ... $builder->add('inStock', ChoiceType::class, [ 'choices' => [ 'In Stock' => true, 'Out of Stock' => false, ], ]);

If there are choice values that are not scalar or the stringified representation is not unique Symfony will use incrementing integers as values. When the form gets submitted the correct values with the correct types will be assigned to the model.

choice_attr

type: array, callable, string or PropertyPath default: []

Use this to add additional HTML attributes to each choice. This can be an associative array where the keys match the choice keys and the values are the attributes for each choice, a callable or a property path (just like choice_label).

If an array, the keys of the choices array must be used as keys:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 use Symfony\Component\Form\Extension\Core\Type\ChoiceType; // ... $builder->add('fruits', ChoiceType::class, [ 'choices' => [ 'Apple' => 1, 'Banana' => 2, 'Durian' => 3, ], 'choice_attr' => [ 'Apple' => ['data-color' => 'Red'], 'Banana' => ['data-color' => 'Yellow'], 'Durian' => ['data-color' => 'Green'], ], ]); // or use a callable $builder->add('attending', ChoiceType::class, [ 'choices' => [ 'Yes' => true, 'No' => false, 'Maybe' => null, ], 'choice_attr' => function ($choice, string $key, mixed $value) { // adds a class like attending_yes, attending_no, etc return ['class' => 'attending_'.strtolower($key)]; }, ]);

Tip

When defining a custom type, you should use the ChoiceList class helper:

1 2 3 4 5 6 7 8 9 use App\Entity\Category; use Symfony\Component\Form\ChoiceList\ChoiceList; // ... $builder->add('choices', ChoiceType::class, [ 'choice_attr' => ChoiceList::attr($this, function (?Category $category): array { return $category ? ['data-uuid' => $category->getUuid()] : []; }), ]);

See the "choice_loader" option documentation.

choice_filter

type: callable, string or PropertyPath default: null

When using predefined choice types from Symfony core or vendor libraries (i.e. CountryType) this option lets you define a callable that takes each choice as the only argument and must return true to keep it or false to discard it:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 // src/Form/Type/AddressType.php namespace App\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\CountryType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class AddressType extends AbstractType { public function configureOptions(OptionsResolver $resolver): void { $resolver ->setDefaults([ // enable this type to accept a limited set of countries 'allowed_countries' => null, ]) ; } public function buildForm(FormBuilderInterface $builder, array $options): void { $allowedCountries = $options['allowed_countries']; $builder // ... ->add('country', CountryType::class, [ // if the AddressType "allowed_countries" option is passed, // use it to create a filter 'choice_filter' => $allowedCountries ? function ($countryCode) use ($allowedCountries): bool { return in_array($countryCode, $allowedCountries, true); } : null, ]) ; }

The option can be a callable or a property path when choices are objects:

1 2 3 4 5 6 7 // ... $builder ->add('category', ChoiceType::class, [ // ... 'choice_filter' => 'isSelectable', ]) ;

Tip

Considering this AddressType could be an entry of a CollectionType you should use the ChoiceList class helper to enable caching:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // src/Form/Type/AddressType.php // ... use Symfony\Component\Form\ChoiceList\ChoiceList; // ... 'choice_filter' => $allowedCountries ? ChoiceList::filter( // pass the type as first argument $this, function (string $countryCode) use ($allowedCountries): bool { return in_array($countryCode, $allowedCountries, true); }, // pass the option that makes the filter "vary" to compute a unique hash $allowedCountries ) : null, // ... choice_label

type: string, callable, false or PropertyPath default: null

By default, the array key of each item in the choices option is used as the text that's shown to the user. The choice_label option allows you to take more control:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 use Symfony\Component\Form\Extension\Core\Type\ChoiceType; // ... $builder->add('attending', ChoiceType::class, [ 'choices' => [ 'yes' => true, 'no' => false, 'maybe' => null, ], 'choice_label' => function ($choice, string $key, mixed $value): TranslatableMessage|string { if (true === $choice) { return 'Definitely!'; } return strtoupper($key); // or if you want to translate some key //return 'form.choice.'.$key; //return new TranslatableMessage($key, false === $choice ? [] : ['%status%' => $value], 'store'); }, ]);

This method is called for each choice, passing you the $choice and $key from the choices array (additional $value is related to choice_value). This will give you:

If your choice values are objects, then choice_label can also be a property path. Imagine you have some Status class with a getDisplayName() method:

1 2 3 4 5 6 7 8 9 10 11 use Symfony\Component\Form\Extension\Core\Type\ChoiceType; // ... $builder->add('attending', ChoiceType::class, [ 'choices' => [ new Status(Status::YES), new Status(Status::NO), new Status(Status::MAYBE), ], 'choice_label' => 'displayName', ]);

If set to false, all the tag labels will be discarded for radio or checkbox inputs. You can also return false from the callable to discard certain labels.

Tip

When defining a custom type, you should use the ChoiceList class helper:

1 2 3 4 5 6 use Symfony\Component\Form\ChoiceList\ChoiceList; // ... $builder->add('choices', ChoiceType::class, [ 'choice_label' => ChoiceList::label($this, 'displayName'), ]);

See the "choice_loader" option documentation.

choice_loader

type: ChoiceLoaderInterface

The choice_loader option can be used instead of the choices option. It allows to create a list lazily or partially when fetching only the choices for a set of submitted values (i.e. querying a search engine like ElasticSearch can be a heavy process).

You can use an instance of CallbackChoiceLoader if you want to take advantage of lazy loading:

1 2 3 4 5 6 7 8 9 10 use App\StaticClass; use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; // ... $builder->add('loaded_choices', ChoiceType::class, [ 'choice_loader' => new CallbackChoiceLoader(static function (): array { return StaticClass::getConstants(); }), ]);

This will cause the call of StaticClass::getConstants() to not happen if the request is redirected and if there is no pre set or submitted data. Otherwise the choice options would need to be resolved thus triggering the callback.

If the built-in CallbackChoiceLoader doesn't fit your needs, you can create your own loader by implementing the ChoiceLoaderInterface or by extending the AbstractChoiceLoader. This abstract class saves you some boilerplate by implementing some methods of the interface so you'll only have to implement the loadChoices() method to have a fully functional choice loader.

When you're defining a custom choice type that may be reused in many fields (like entries of a collection) or reused in multiple forms at once, you should use the ChoiceList static methods to wrap the loader and make the choice list cacheable for better performance:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 use App\Form\ChoiceList\CustomChoiceLoader; use App\StaticClass; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\ChoiceList\ChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class ConstantsType extends AbstractType { public function getParent(): string { return ChoiceType::class; } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ // the example below will create a CallbackChoiceLoader from the callable 'choice_loader' => ChoiceList::lazy($this, function () { return StaticClass::getConstants(); }), // you can pass your own loader as well, depending on other options 'some_key' => null, 'choice_loader' => function (Options $options): ChoiceLoaderInterface { return ChoiceList::loader( // pass the instance of the type or type extension which is // currently configuring the choice list as first argument $this, // pass the other option to the loader new CustomChoiceLoader($options['some_key']), // ensure the type stores a loader per key // by using the special third argument "$vary" // an array containing anything that "changes" the loader [$options['some_key']] ); }, ]); } } choice_name

type: callable, string or PropertyPath default: null

Controls the internal field name of the choice. You normally don't care about this, but in some advanced cases, you might. For example, this "name" becomes the index of the choice views in the template and is used as part of the field name attribute.

This can be a callable or a property path. See choice_label for similar usage. By default, the choice key or an incrementing integer may be used (starting at 0).

Tip

When defining a custom type, you should use the ChoiceList class helper:

1 2 3 4 5 6 use Symfony\Component\Form\ChoiceList\ChoiceList; // ... $builder->add('choices', ChoiceType::class, [ 'choice_name' => ChoiceList::fieldName($this, 'name'), ]);

See the "choice_loader" option documentation.

Caution

The configured value must be a valid form name. Make sure to only return valid names when using a callable. Valid form names must be composed of letters, digits, underscores, dashes and colons and must not start with a dash or a colon.

choice_translation_domain

type: string, boolean or null default: true

This option determines if the choice values should be translated and in which translation domain.

The values of the choice_translation_domain option can be true (reuse the current translation domain), false (disable translation), null (uses the parent translation domain or the default domain) or a string which represents the exact translation domain to use.

choice_translation_parameters

type: array, callable, string or PropertyPath default: []

The choice values are translated before displaying it, so it can contain translation placeholders. This option defines the values used to replace those placeholders. This can be an associative array where the keys match the choice keys and the values are the attributes for each choice, a callable or a property path (just like choice_label).

Given this translation message:

1 2 3 # translations/messages.en.yaml form.order.yes: 'I confirm my order to the company %company%' form.order.no: 'I cancel my order' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 form.order.yes I confirm my order to the company %company% form.order.no I cancel my order 1 2 3 4 5 // translations/messages.fr.php return [ 'form.order.yes' => "I confirm my order to the company %company%", 'form.order.no' => "I cancel my order", ];

You can specify the placeholder values as follows:

1 2 3 4 5 6 7 8 9 10 11 12 13 $builder->add('id', null, [ 'choices' => [ 'form.order.yes' => true, 'form.order.no' => false, ], 'choice_translation_parameters' => function ($choice, string $key, mixed $value): array { if (false === $choice) { return []; } return ['%company%' => 'ACME Inc.']; }, ]);

If an array, the keys of the choices array must be used as keys:

1 2 3 4 5 6 7 8 9 10 $builder->add('id', null, [ 'choices' => [ 'form.order.yes' => true, 'form.order.no' => false, ], 'choice_translation_parameters' => [ 'form.order.yes' => ['%company%' => 'ACME Inc.'], 'form.order.no' => [], ], ]);

The translation parameters of child fields are merged with the same option of their parents, so children can reuse and/or override any of the parent placeholders.

choice_value

type: callable, string or PropertyPath default: null

Returns the string "value" for each choice, which must be unique across all choices. This is used in the value attribute in HTML and submitted in the POST/PUT requests. You don't normally need to worry about this, but it might be handy when processing an API request (since you can configure the value that will be sent in the API request).

This can be a callable or a property path. By default, the choices are used if they can be casted to strings. Otherwise an incrementing integer is used (starting at 0).

If you pass a callable, it will receive one argument: the choice itself. When using the EntityType Field, the argument will be the entity object for each choice or null in a placeholder is used, which you need to handle:

1 2 3 'choice_value' => function (?MyOptionEntity $entity): string { return $entity ? $entity->getId() : ''; },

Tip

When defining a custom type, you should use the ChoiceList class helper:

1 2 3 4 5 6 use Symfony\Component\Form\ChoiceList\ChoiceList; // ... $builder->add('choices', ChoiceType::class, [ 'choice_value' => ChoiceList::value($this, 'uuid'), ]);

See the "choice_loader" option documentation.

duplicate_preferred_choices

type: boolean default: true

When using the preferred_choices option, those preferred choices are displayed twice by default: at the top of the list and in the full list below. Set this option to false, to only display preferred choices at the top of the list:

1 2 3 4 5 6 7 8 9 10 11 12 13 use Symfony\Component\Form\Extension\Core\Type\ChoiceType; // ... $builder->add('language', ChoiceType::class, [ 'choices' => [ 'English' => 'en', 'Spanish' => 'es', 'Bork' => 'muppets', 'Pirate' => 'arr', ], 'preferred_choices' => ['muppets', 'arr'], 'duplicate_preferred_choices' => false, ]); expanded

type: boolean default: false

If set to true, radio buttons or checkboxes will be rendered (depending on the multiple value). If false, a select element will be rendered.

group_by

type: string, callable or PropertyPath default: null

You can group the elements of a into by passing a multi-dimensional array to choices. See the Grouping Options section about that.

The group_by option is an alternative way to group choices, which gives you a bit more flexibility.

Take the following example:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 use Symfony\Component\Form\Extension\Core\Type\ChoiceType; // ... $builder->add('publishAt', ChoiceType::class, [ 'choices' => [ 'now' => new \DateTime('now'), 'tomorrow' => new \DateTime('+1 day'), '1 week' => new \DateTime('+1 week'), '1 month' => new \DateTime('+1 month'), ], 'group_by' => function($choice, $key, $value) { if ($choice


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3